Skip to content

[FEATURE] add lifter, a low-pass filter in the cepstral domain - #119

Open
aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-lifter
Open

aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-lifter

Conversation

@aguirreSL

Copy link
Copy Markdown

Adds lifter(signal, n=None, alpha=0) to pytta.functions, the low-pass lifter of ita_lifter of the ITA-Toolbox. The complex cepstrum of each channel (cepstrum of #80, which removes the integer delay) is multiplied by a Tukey window of 2n + 1 quefrencies centred on zero, from rectangular (alpha 0) to Hann (alpha 1), and transformed back with the delay (icepstrum). This smooths the log magnitude and the phase of the spectrum together. n defaults to a quarter of the length, as in the ITA-Toolbox, and from half the length on nothing is done.

The ITA-Toolbox also shifts an energy signal to its start and windows it before the cepstrum, to help the phase unwrapping; here cepstrum already removes the integer delay, so that step is left out. The ITA code was read for its semantics only and nothing was copied.

This pull request builds on #80 and shows its commit until #80 is merged.

The tests in tests/test_lifter.py use an echo, h = δ + 0.5 δ(n - 100), whose complex cepstrum lies only at multiples of 100 samples:

  1. A lifter of 50 quefrencies removes the echo and leaves the impulse, with the rectangular and the Hann window (1.1e-14).
  2. A rectangular lifter of 2000 quefrencies leaves the response as it was (1.2e-9).

Checked with Python 3.12, numpy 1.26 and scipy 1.17. The 7 failures of development (3 in test_h5io.py, 4 in test_pyttasave.py) are the same with and without this change.

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com

aguirreSL and others added 2 commits October 31, 2026 21:53
group_delay(signal) returns the group delay of each channel in seconds,
from the derivative of the spectrum, Re{DFT(n x[n]) / DFT(x[n])} / fs,
which needs no phase unwrapping.

coherence(x, y, winSize=1024) returns the magnitude squared coherence
with scipy.signal.coherence (Welch, Hann, 50 % overlap). Channels are
paired one to one, and a single channel is paired with all of the other.

cepstrum(signal, kind='complex') returns the real or complex cepstrum.
For the complex one the integer linear phase is removed first and
returned, and icepstrum(cepstrumObj, delay) inverts it. The magnitude
floor is the same as in minimum_phase.

generate.mls(order, samplingRate) returns one period of a symmetrical
MLS from scipy.signal.max_len_seq, and mls_deconvolution(response,
order) recovers the impulse response by periodic cross-correlation
normalized by L + 1. With more than one period the first is dropped and
the others are averaged.

Tests pin the group delay of a pure delay and of a first order allpass,
the coherence of a noisy filtered signal against SNR / (1 + SNR), the
cepstra of a minimum phase filter against the analytic series, the
complex cepstrum round trip with its delay, the exact MLS
autocorrelation and the deconvolution of a FIR with its known offset
-sum(h) / (L + 1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant